# _*_ coding:utf-8 _*_
import pandas as pd
import pynmea2
from numpy import mean
import numpy as np
from pandas import Series
from pynmea2 import RMC, GSV
from collections import defaultdict


class gnss(object):
    '''
    Purpose    :  processing every GNSS sentence in NMEA
    '''

    def __init__(self, GNSS):
        # SVinfo = dict()
        SVinfo = defaultdict(list)
        allFreqCNO = []
        for sentence in GNSS:
            svid = sentence.data[3:-1:4]
            svcno = [int(x) for x in sentence.data[6:-1:4]]
            svele = [x for x in sentence.data[4:-1:4]]
            svazi = [x for x in sentence.data[5:-1:4]]
            allFreqCNO += svcno
            i = 0
            for sv in svid:
                if sv not in SVinfo:
                    SVinfo[sv].append(svcno[i])
                    SVinfo[sv].append(svele[i])
                    SVinfo[sv].append(svazi[i])
                elif svcno[i] > SVinfo[sv][0]:
                    SVinfo[sv][0] = svcno[i]
                i = i + 1
        self.SVinfo = SVinfo
        self.SVnum = len(SVinfo)
        self.allFreqCNO = allFreqCNO

    def getcno(self):
        for key in self.SVinfo.keys():
            if len(self.SVinfo[key]) == 2:
                pass


class nmeaMoment(object):
    '''
    Purpose    : processing the single moment of GNSS receiver measurements
    '''

    def __init__(self, Moment, label):

        self.utc = Moment[0].data[0]

        talkerID = ['GP', 'GL', 'GA', 'GB', 'GQ']
        cno = []
        allFreqCNO = []
        cnoeleazi = []
        self.GPSVnum = self.GLSVnum = self.GASVnum = self.GBSVnum = self.GQSVnum = 0
        self.GPaveCNO = self.GLaveCNO = self.GAaveCNO = self.GBaveCNO = self.GQaveCNO = 0
        for talkerr in talkerID:
            locals()[talkerr] = gnss([sentence for sentence in Moment if sentence.talker == talkerr])
            # cno+=list(locals()[talkerr].SVinfo.values())
            cno += [xx[0] for xx in locals()[talkerr].SVinfo.values()]
            cnoeleazi += list(locals()[talkerr].SVinfo.values())
            allFreqCNO += locals()[talkerr].allFreqCNO
            if talkerr == 'GP':
                self.GPSVnum = locals()[talkerr].SVnum
                self.GPaveCNO = mean(locals()[talkerr].allFreqCNO)
            elif talkerr == 'GL':
                self.GLSVnum = locals()[talkerr].SVnum
                self.GLaveCNO = mean(locals()[talkerr].allFreqCNO)
            elif talkerr == 'GA':
                self.GASVnum = locals()[talkerr].SVnum
                self.GAaveCNO = mean(locals()[talkerr].allFreqCNO)
            elif talkerr == 'GB':
                self.GBSVnum = locals()[talkerr].SVnum
                self.GBaveCNO = mean(locals()[talkerr].allFreqCNO)
            elif talkerr == 'GQ':
                self.GQSVnum = locals()[talkerr].SVnum
                self.GQaveCNO = mean(locals()[talkerr].allFreqCNO)

            # self.[locals()[talkerr + 'aveCNO']] =mean(locals()[talkerr].allFreqCNO)
            # len(locals()[talkerr].SVinfo)
        self.cno = Series(cno)
        self.label = label
        self.num = len(cno)
        self.allFreqCNO = allFreqCNO
        self.cnoeleazi = cnoeleazi

    def xt(self):  # feature extraction
        try:
            q75, q25 = np.percentile(self.cno, [75, 25])
        except IndexError as e:

            xt = [self.utc,
                  self.num,
                  0,
                  0,
                  0,
                  0,
                  0,
                  0,
                  0,
                  0,
                  7,
                  self.label]
            return xt
        iqr = q75 - q25

        cnoeleazi = list(filter(lambda x: x[1] != '', self.cnoeleazi))

        for x in cnoeleazi:
            x[1] = int(x[1])
            x[2] = int(x[2])


######################  ratio
        cc = np.zeros((2, 181))
        i = 0
        for azi in np.arange(-0.5, 180.5, 1):
            xx1 = []
            xx2 = []
            for xx in cnoeleazi:
                if (xx[2] > azi and xx[2] <= azi + 180) or (xx[2] > -0.5 and xx[2] <= azi - 180):
                    xx1.append(xx)
                else:
                    xx2.append(xx)
            if xx1 == [] or xx2 == []:
                self.ratio = 7
            else:
                aa = np.array(xx1)[:, 0].sum()
                bb = np.array(xx2)[:, 0].sum()
                cc[0, i] = aa / bb
                cc[1, i] = bb / aa
                if cc.max() > 7:
                    self.ratio = 7
                else:
                    self.ratio = cc.max()

                if aa == 0 and bb == 0:
                    print('aa==0 and bb==0')
                    self.ratio = 7

            i += 1


 ######################
 # feature vector
 
        xt = [self.utc,
              self.num,
              self.cno.mean(),
              self.cno.std(),
              self.cno.max(),
              self.cno.min(),
              self.cno.skew(),
              self.cno.kurt(),
              self.cno.median(),
              iqr,
              self.ratio,
              self.label]

        return xt


def readNMEA(path):
    '''
    Purpose    :  read the GNSS receiver measurements in NMEA format
    '''
    print('正在处理：' + path)
    Path = path.split("/")[-1]
    label = int(Path[0])

    records = []

    with pynmea2.NMEAFile(path) as nmea_file:
        iii = 1
        for recordd in nmea_file:
            iii += 1
            print(iii)
            records.append(recordd)
    records = [element for element in records if
               isinstance(element, RMC) or (isinstance(element, GSV) and element.data[-1] != '0')]
    i, ii = 0, 0
    for element in records[:1500]:
        if isinstance(element, RMC):
            i += 1
            if i == 20:
                print('已过滤前4s数据')  # filter the first 4s data

                break
        ii += 1

    records = records[ii:]
    i = 0
    index = []
    for element in records:
        if isinstance(element, RMC):
            index.append(i)
        i += 1

    records = [records[index[i]:index[i + 1]] for i in range(len(index) - 1)]
    log = []
    allFreqCNO = []
    GPSVnum = [];
    GLSVnum = [];
    GASVnum = [];
    GBSVnum = [];
    GQSVnum = []
    GPaveCNO = [];
    GLaveCNO = [];
    GAaveCNO = [];
    GBaveCNO = [];
    GQaveCNO = []
    iii = 0
    for e in records:
        nmeaMomenttt = nmeaMoment(e, label)
        log.append(nmeaMomenttt.xt())
        GPSVnum.append(nmeaMomenttt.GPSVnum);
        GLSVnum.append(nmeaMomenttt.GLSVnum);
        GASVnum.append(nmeaMomenttt.GASVnum);
        GBSVnum.append(nmeaMomenttt.GBSVnum);
        GQSVnum.append(nmeaMomenttt.GQSVnum);
        GPaveCNO.append(nmeaMomenttt.GPaveCNO)
        GLaveCNO.append(nmeaMomenttt.GLaveCNO)
        GAaveCNO.append(nmeaMomenttt.GAaveCNO)
        GBaveCNO.append(nmeaMomenttt.GBaveCNO)
        GQaveCNO.append(nmeaMomenttt.GQaveCNO)

        iii += 1
        # print(iii)

        allFreqCNO += nmeaMomenttt.allFreqCNO
    items = ['utc', 'num', 'mean', 'std', 'max', 'min', 'skew', 'kurt', 'median', 'iqr', 'ratio', 'label']
    log = pd.DataFrame(log, columns=items)

    log.iloc[:, 1:] = log.iloc[:, 1:].fillna(log.iloc[:, 1:].mean())

    SVnum = [mean(GPSVnum), mean(GLSVnum), mean(GASVnum), mean(GBSVnum), mean(GQSVnum)]
    aveCNO = [mean(GPaveCNO), mean(GLaveCNO), mean(GAaveCNO), mean(GBaveCNO), mean(GQaveCNO)]
    print('     Finished：' + path)
    return log, allFreqCNO, label, SVnum, aveCNO


